/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   PlayerPrefsViewer.cs
 * CreateData   :   2024/5/29 23:50:30
 * UnityVersion :   2021.3.30f1c1
 * Description  :   PlayerPrefs 数据查看器
************************************************/

using Sirenix.OdinInspector;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.Text.RegularExpressions;

/// <summary>
/// PlayerPrefs 数据查看器
/// </summary>
public class PlayerPrefsViewer
{
    [Title("Head")]
    [LabelWidth(150), Multiline]
    public string _Description = "PlayerPrefs 数据查看器";
    [Title("查看列表")]
    private string keyStr = "";
    private string valueStr;
    private Vector2 scrollViewSize = new Vector2(100, 100);
    private List<PlayerPrefsItem> arr = new List<PlayerPrefsItem>();
    private string rexPattern = @"(^$)|(^[a-zA-Z0-9 ,.;:<>_|!§$%&/()=?*+~#-]+$)";
    [OnInspectorGUI]
    private void OnGUI()
    {
        GUILayout.Space(10);
        // 绘制
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("输入添加/修改的键值对", GUILayout.Width(150));

            //绘制输入框:
            keyStr = GUILayout.TextField(keyStr, GUILayout.Width(150));
            EditorGUILayout.LabelField(":", GUILayout.Width(5));
            valueStr = GUILayout.TextField(valueStr, GUILayout.ExpandWidth(true));

            GUI.enabled = Regex.IsMatch(keyStr, rexPattern);
            //绘制 清空输入 按钮
            if (GUILayout.Button("应用", GUILayout.Width(40)))
            {
                if (!string.IsNullOrEmpty(keyStr) && !string.IsNullOrEmpty(valueStr))
                {
                    if (valueStr.Contains("."))
                    {
                        if (float.TryParse(valueStr, out float value))
                        {
                            PlayerPrefs.SetFloat(keyStr, value);
                        }
                        else
                        {
                            PlayerPrefs.SetString(keyStr, valueStr);
                        }
                    }
                    else
                    {
                        if (int.TryParse(valueStr, out int value))
                        {
                            PlayerPrefs.SetInt(keyStr, value);
                        }
                        else
                        {
                            PlayerPrefs.SetString(keyStr, valueStr);
                        }
                    }
                }
            }
            GUI.enabled = true;
            //绘制 删除所有Key 按钮
            if (GUILayout.Button("删除所有", GUILayout.Width(60)))
            {
                if (EditorUtility.DisplayDialog("删除提示", "确认删除所有key吗？", "确定", "取消"))
                {
                    PlayerPrefs.DeleteAll();
                };
            }
            EditorGUILayout.EndHorizontal();
        }
        GUILayout.Space(10);
        // 列表
        {
            GetAll(PlayerSettings.companyName, PlayerSettings.productName);
            scrollViewSize = GUILayout.BeginScrollView(scrollViewSize, false, true);
            foreach (var item in arr)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label(item.key, GUILayout.Width(150));
                GUILayout.TextField(item.value.ToString(), GUILayout.ExpandWidth(true));
                Type type = item.value.GetType();
                GUILayout.Label(type.Name, GUILayout.Width(60));
                if (GUILayout.Button("X", GUILayout.Width(25)))
                {
                    PlayerPrefs.DeleteKey(item.key);
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.EndScrollView();
        }
    }

    /// <summary>
    /// 获取所有 PlayerPrefs 数据
    /// </summary>
    /// <param name="companyName">公司名</param>
    /// <param name="productName">项目名</param>
    /// <exception cref="NotSupportedException"></exception>
    public void GetAll(string companyName, string productName)
    {
        arr.Clear();
        if (Application.platform == RuntimePlatform.WindowsEditor)
        {
            // From Unity docs: On Windows, PlayerPrefs are stored in the registry under HKCU\Software\[company name]\[product name] key, where company and product names are the names set up in Project Settings.
#if UNITY_5_5_OR_NEWER
            Microsoft.Win32.RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Unity\\UnityEditor\\" + companyName + "\\" + productName);
#else
            Microsoft.Win32.RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\" + companyName + "\\" + productName);
#endif
            if (registryKey != null)
            {
                // Get an array of what keys (registry value names) are stored
                string[] valueNames = registryKey.GetValueNames();

                foreach (string valueName in valueNames)
                {
                    string key = valueName;
                    // Remove the _h193410979 style suffix used on player pref keys in Windows registry
                    int index = key.LastIndexOf("_");
                    key = key.Remove(index, key.Length - index);

                    // Get the value from the registry
                    object ambiguousValue = registryKey.GetValue(valueName);

                    // Unfortunately floats will come back as an int (at least on 64 bit) because the float is stored as
                    // 64 bit but marked as 32 bit - which confuses the GetValue() method greatly! 
                    if (ambiguousValue.GetType() == typeof(Int32))
                    {
                        ambiguousValue = PlayerPrefs.GetInt(key);
                    }
                    if (ambiguousValue.GetType() == typeof(Int64))
                    {
                        ambiguousValue = PlayerPrefs.GetFloat(key);
                    }
                    else if (ambiguousValue.GetType() == typeof(byte[]))
                    {
                        ambiguousValue = System.Text.Encoding.Default.GetString((byte[])ambiguousValue);
                    }
                    arr.Add(new PlayerPrefsItem(key, ambiguousValue));
                }
            }
            else
            {
                // 没有保存现有的玩家偏好（这是有效的）
            }
        }
        else if (Application.platform == RuntimePlatform.OSXEditor)
        {
            throw new NotSupportedException("不支持当前平台！");
        }
        else if (Application.platform == RuntimePlatform.LinuxEditor)
        {
            throw new NotSupportedException("不支持当前平台！");
        }
        else
        {
            throw new NotSupportedException("不支持当前平台！");
        }
    }

    [Serializable]
    public struct PlayerPrefsItem
    {
        public PlayerPrefsItem(string _key, object _value)
        {
            key = _key;
            value = _value;
        }
        public string key;
        public object value;
    }
}
